package com.dap.dubbo.rpc.filter;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.remoting.TimeoutException;
import com.alibaba.dubbo.rpc.*;
import com.dap.dubbo.rpc.config.RedisConfig;
import redis.clients.jedis.Jedis;

import java.util.UUID;

@Activate(group = Constants.CONSUMER)
public class TimeOutFilter implements Filter {
    public static final String DUBBO_APPLICATION_KEY = "Application:";
    /**
     * 错误数量
     */
    public static final int TimeOutErrorNumber=500;
    /**
     * 错误登记时间间隔
     */
    public  int interval=3000;
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation)  throws RpcException{
        Jedis jedis = RedisConfig.getJedis();
        String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
        String timeInterval = jedis.get(DUBBO_APPLICATION_KEY+ application+":TimeOutErrorInterval" );
        if(timeInterval!=null && !"".equals(timeInterval)){
            interval=Integer.valueOf(timeInterval);
        }
        long now = System.currentTimeMillis();
        String key=DUBBO_APPLICATION_KEY+ application+":TimeOutErrorNumber";
        jedis.zremrangeByScore(key.getBytes(), "-inf".getBytes(),
                String.valueOf(now - interval).getBytes());
        Long count=jedis.scard(key);
        if(count!=null && count>TimeOutErrorNumber){
            /**
             * 拒绝服务
             */
            if (jedis != null) {
                jedis.close();
            }
            return new RpcResult(new Exception("超时过多拒绝服务"));
        }
        try {
              Result result = invoker.invoke(invocation);
              return result;
          }catch (Exception e){
              if(e.getCause() instanceof  TimeoutException) {
                  String identifier = UUID.randomUUID().toString();
                  jedis.zadd(key,now,identifier);
              }
              throw e;
          }finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
}
